/**
 **************************************************************************
 * @file     custom_hid_desc.c
 * @version  v2.1.2
 * @date     2022-08-16
 * @brief    usb hid device descriptor
 **************************************************************************
 *                       Copyright notice & Disclaimer
 *
 * The software Board Support Package (BSP) that is made available to
 * download from Artery official website is the copyrighted work of Artery.
 * Artery authorizes customers to use, copy, and distribute the BSP
 * software and its related documentation for the purpose of design and
 * development in conjunction with Artery microcontrollers. Use of the
 * software is governed by this copyright notice and the following disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
 * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
 * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
 * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
 * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 *
 **************************************************************************
 */
#include "usb_std.h"
#include "usbd_sdr.h"
#include "usbd_core.h"
#include "custom_hid_desc.h"

/** @addtogroup AT32F403A_407_middlewares_usbd_class
 * @{
 */

/** @defgroup USB_custom_hid_desc
 * @brief usb device custom_hid descriptor
 * @{
 */

/** @defgroup USB_custom_hid_desc_private_functions
 * @{
 */
static usbd_desc_t *get_device_descriptor(void);
static usbd_desc_t *get_device_qualifier(void);
static usbd_desc_t *get_device_configuration(void);
static usbd_desc_t *get_device_other_speed(void);
static usbd_desc_t *get_device_lang_id(void);
static usbd_desc_t *get_device_manufacturer_string(void);
static usbd_desc_t *get_device_product_string(void);
static usbd_desc_t *get_device_serial_string(void);
static usbd_desc_t *get_device_interface_string(void);
static usbd_desc_t *get_device_config_string(void);

static uint16_t usbd_unicode_convert(uint8_t *string, uint8_t *unicode_buf);
static void usbd_int_to_unicode(uint32_t value, uint8_t *pbuf, uint8_t len);
static void get_serial_num(void);
static uint8_t g_usbd_desc_buffer[256];

/**
 * @brief  custom hid device descriptor handler structure
 */
usbd_desc_handler custom_hid_desc_handler =
    {
        get_device_descriptor,
        get_device_qualifier,
        get_device_configuration,
        get_device_other_speed,
        get_device_lang_id,
        get_device_manufacturer_string,
        get_device_product_string,
        get_device_serial_string,
        get_device_interface_string,
        get_device_config_string,
};

/**
 * @brief usb device standard descriptor
 */
#if defined(__ICCARM__) /* iar compiler */
#pragma data_alignment = 4
#endif
ALIGNED_HEAD static uint8_t g_usbd_descriptor[USB_DEVICE_DESC_LEN] ALIGNED_TAIL =
    {
        USB_DEVICE_DESC_LEN,       /* bLength */
        USB_DESCIPTOR_TYPE_DEVICE, /* bDescriptorType */
        0x00,                      /* bcdUSB */
        0x02,
        0x00,                          /* bDeviceClass */
        0x00,                          /* bDeviceSubClass */
        0x00,                          /* bDeviceProtocol */
        USB_MAX_EP0_SIZE,              /* bMaxPacketSize */
        LBYTE(USBD_CUSHID_VENDOR_ID),  /* idVendor */
        HBYTE(USBD_CUSHID_VENDOR_ID),  /* idVendor */
        LBYTE(USBD_CUSHID_PRODUCT_ID), /* idProduct */
        HBYTE(USBD_CUSHID_PRODUCT_ID), /* idProduct */
        0x00,                          /* bcdDevice rel. 2.00 */
        0x02,
        USB_MFC_STRING,     /* Index of manufacturer string */
        USB_PRODUCT_STRING, /* Index of product string */
        USB_SERIAL_STRING,  /* Index of serial number string */
        1                   /* bNumConfigurations */
};

/**
 * @brief usb configuration standard descriptor
 */
#if defined(__ICCARM__) /* iar compiler */
#pragma data_alignment = 4
#endif
ALIGNED_HEAD static uint8_t g_usbd_configuration[USBD_CUSHID_CONFIG_DESC_SIZE] ALIGNED_TAIL =
    {
        USB_DEVICE_CFG_DESC_LEN,             /* bLength: configuration descriptor size */
        USB_DESCIPTOR_TYPE_CONFIGURATION,    /* bDescriptorType: configuration */
        LBYTE(USBD_CUSHID_CONFIG_DESC_SIZE), /* wTotalLength: bytes returned */
        HBYTE(USBD_CUSHID_CONFIG_DESC_SIZE), /* wTotalLength: bytes returned */
        0x01,                                /* bNumInterfaces: 1 interface */
        0x01,                                /* bConfigurationValue: configuration value */
        0x00,                                /* iConfiguration: index of string descriptor describing
                                                the configuration */
        0xC0,                                /* bmAttributes: self powered */
        0x32,                                /* MaxPower 100 mA: this current is used for detecting vbus */

        USB_DEVICE_IF_DESC_LEN,       /* bLength: interface descriptor size */
        USB_DESCIPTOR_TYPE_INTERFACE, /* bDescriptorType: interface descriptor type */
        0x00,                         /* bInterfaceNumber: number of interface */
        0x00,                         /* bAlternateSetting: alternate set */
        0x02,                         /* bNumEndpoints: number of endpoints */
        USB_CLASS_CODE_HID,           /* bInterfaceClass: class code hid */
        0x01,                         /* bInterfaceSubClass: subclass code */
        0x01,                         /* bInterfaceProtocol: protocol code */
        0x00,                         /* iInterface: index of string descriptor */

        0x09,               /* bLength: size of HID descriptor in bytes */
        HID_CLASS_DESC_HID, /* bDescriptorType: HID descriptor type */
        LBYTE(CUSHID_BCD_NUM),
        HBYTE(CUSHID_BCD_NUM), /* bcdHID: HID class specification release number */
        0x00,                  /* bCountryCode: hardware target conutry */
        0x01,                  /* bNumDescriptors: number of HID class descriptor to follow */
        HID_CLASS_DESC_REPORT, /* bDescriptorType: report descriptor type */
        LBYTE(sizeof(g_usbd_custom_hid_report)),
        HBYTE(sizeof(g_usbd_custom_hid_report)), /* wDescriptorLength: total length of reprot descriptor */

        USB_DEVICE_EPT_LEN,          /* bLength: size of endpoint descriptor in bytes */
        USB_DESCIPTOR_TYPE_ENDPOINT, /* bDescriptorType: endpoint descriptor type */
        USBD_CUSTOM_HID_IN_EPT,      /* bEndpointAddress: the address of endpoint on usb device described by this descriptor */
        USB_EPT_DESC_INTERRUPT,      /* bmAttributes: endpoint attributes */
        LBYTE(USBD_CUSTOM_IN_MAXPACKET_SIZE),
        HBYTE(USBD_CUSTOM_IN_MAXPACKET_SIZE), /* wMaxPacketSize: maximum packe size this endpoint */
        CUSHID_BINTERVAL_TIME,                /* bInterval: interval for polling endpoint for data transfers */

        USB_DEVICE_EPT_LEN,          /* bLength: size of endpoint descriptor in bytes */
        USB_DESCIPTOR_TYPE_ENDPOINT, /* bDescriptorType: endpoint descriptor type */
        USBD_CUSTOM_HID_OUT_EPT,     /* bEndpointAddress: the address of endpoint on usb device described by this descriptor */
        USB_EPT_DESC_INTERRUPT,      /* bmAttributes: endpoint attributes */
        LBYTE(USBD_CUSTOM_OUT_MAXPACKET_SIZE),
        HBYTE(USBD_CUSTOM_OUT_MAXPACKET_SIZE), /* wMaxPacketSize: maximum packe size this endpoint */
        CUSHID_BINTERVAL_TIME,                 /* bInterval: interval for polling endpoint for data transfers */
};

/**
 * @brief usb hid report descriptor
 */
#if defined(__ICCARM__) /* iar compiler */
#pragma data_alignment = 4
#endif
ALIGNED_HEAD uint8_t g_usbd_custom_hid_report[USBD_CUSHID_SIZ_REPORT_DESC] ALIGNED_TAIL =
    {
        0x05, 0x01,                   // Usage Page (Generic Desktop Ctrls)
        0x09, 0x04,                   // Usage (Joystick)
        0xA1, 0x01,                   // Collection (Application)
        0x85, 0x01,                   //   Report ID (1)
        0x09, 0x39,                   //   Usage (Hat switch)
        0x15, 0x01,                   //   Logical Minimum (1)
        0x25, 0x08,                   //   Logical Maximum (8)
        0x75, 0x08,                   //   Report Size (8)
        0x95, 0x01,                   //   Report Count (1)
        0x81, 0x02,                   //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x05, 0x09,                   //   Usage Page (Button)
        0x19, 0x01,                   //   Usage Minimum (0x01)
        0x29, 0x10,                   //   Usage Maximum (0x10)
        0x15, 0x00,                   //   Logical Minimum (0)
        0x25, 0x01,                   //   Logical Maximum (1)
        0x75, 0x01,                   //   Report Size (1)
        0x95, 0x10,                   //   Report Count (16)
        0x81, 0x02,                   //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x05, 0x01,                   //   Usage Page (Generic Desktop Ctrls)
        0x09, 0x33,                   //   Usage (Rx)
        0x09, 0x34,                   //   Usage (Ry)
        0x16, 0x00, 0x00,             //   Logical Minimum (0)
        0x27, 0xFF, 0xFF, 0x00, 0x00, //   Logical Maximum (65534)
        0x35, 0x00,                   //   Physical Minimum (0)
        0x47, 0xFF, 0xFF, 0x00, 0x00, //   Physical Maximum (65534)
        0x75, 0x10,                   //   Report Size (16)
        0x95, 0x02,                   //   Report Count (2)
        0x81, 0x02,                   //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x09, 0x30,                   //   Usage (X)
        0x09, 0x31,                   //   Usage (Y)
        0x09, 0x38,                   //   Usage (Wheel)
        0x16, 0x00, 0x80,             //   Logical Minimum (-32768)
        0x26, 0xFF, 0x7F,             //   Logical Maximum (32767)
        0x36, 0x00, 0x80,             //   Physical Minimum (-32768)
        0x46, 0xFF, 0x7F,             //   Physical Maximum (32767)
        0x75, 0x10,                   //   Report Size (16)
        0x95, 0x03,                   //   Report Count (3)
        0x81, 0x02,                   //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x05, 0x02,                   //   Usage Page (Sim Ctrls)
        0x09, 0xBB,                   //   Usage (Throttle)
        0x09, 0xC5,                   //   Usage (Brake)
        0x09, 0xC7,
        0x16, 0x00, 0x00,             //   Logical Minimum (0)
        0x27, 0xFF, 0xFF, 0x00, 0x00, //   Logical Maximum (65534)
        0x35, 0x00,                   //   Physical Minimum (0)
        0x47, 0xFF, 0xFF, 0x00, 0x00, //   Physical Maximum (65534)
        0x75, 0x10,                   //   Report Size (16)
        0x95, 0x03,                   //   Report Count (2)
        0x81, 0x02,                   //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)

        0x05, 0x0F,                   //   Usage Page (PID Page)
        0x09, 0x92,                   //   Usage (0x92)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x02,                   //     Report ID (2)
        0x09, 0x9F,                   //     Usage (0x9F)
        0x09, 0xA0,                   //     Usage (0xA0)
        0x09, 0xA4,                   //     Usage (0xA4)
        0x09, 0xA5,                   //     Usage (0xA5)
        0x09, 0xA6,                   //     Usage (0xA6)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x25, 0x01,                   //     Logical Maximum (1)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x45, 0x01,                   //     Physical Maximum (1)
        0x75, 0x01,                   //     Report Size (1)
        0x95, 0x05,                   //     Report Count (5)
        0x81, 0x02,                   //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x95, 0x03,                   //     Report Count (3)
        0x81, 0x03,                   //     Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x09, 0x94,                   //     Usage (0x94)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x25, 0x01,                   //     Logical Maximum (1)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x45, 0x01,                   //     Physical Maximum (1)
        0x75, 0x01,                   //     Report Size (1)
        0x95, 0x01,                   //     Report Count (1)
        0x81, 0x02,                   //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0x09, 0x22,                   //     Usage (0x22)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x25, 0x28,                   //     Logical Maximum (40)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x28,                   //     Physical Maximum (40)
        0x75, 0x07,                   //     Report Size (7)
        0x95, 0x01,                   //     Report Count (1)
        0x81, 0x02,                   //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
        0xC0,                         //   End Collection
        0x09, 0x21,                   //   Usage (0x21)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x01,                   //     Report ID (1)
        0x09, 0x22,                   //     Usage (0x22)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x25, 0x28,                   //     Logical Maximum (40)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x28,                   //     Physical Maximum (40)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x25,                   //     Usage (0x25)
        0xA1, 0x02,                   //     Collection (Logical)
        0x09, 0x26,                   //       Usage (0x26)
        0x09, 0x27,                   //       Usage (0x27)
        0x09, 0x30,                   //       Usage (0x30)
        0x09, 0x31,                   //       Usage (0x31)
        0x09, 0x32,                   //       Usage (0x32)
        0x09, 0x33,                   //       Usage (0x33)
        0x09, 0x34,                   //       Usage (0x34)
        0x09, 0x40,                   //       Usage (0x40)
        0x09, 0x41,                   //       Usage (0x41)
        0x09, 0x42,                   //       Usage (0x42)
        0x09, 0x43,                   //       Usage (0x43)
        0x25, 0x0B,                   //       Logical Maximum (11)
        0x15, 0x01,                   //       Logical Minimum (1)
        0x35, 0x01,                   //       Physical Minimum (1)
        0x45, 0x0B,                   //       Physical Maximum (11)
        0x75, 0x08,                   //       Report Size (8)
        0x95, 0x01,                   //       Report Count (1)
        0x91, 0x00,                   //       Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //     End Collection
        0x09, 0x50,                   //     Usage (0x50)
        0x09, 0x54,                   //     Usage (0x54)
        0x09, 0x51,                   //     Usage (0x51)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x26, 0x10, 0x27,             //     Logical Maximum (10000)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x66, 0x03, 0x10,             //     Unit (System: English Linear, Time: Seconds)
        0x55, 0xFD,                   //     Unit Exponent
        0x75, 0x10,                   //     Report Size (16)
        0x95, 0x03,                   //     Report Count (3)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x55, 0x00,                   //     Unit Exponent (0)
        0x66, 0x00, 0x00,             //     Unit (None)
        0x09, 0x52,                   //     Usage (0x52)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x26, 0x10, 0x27,             //     Logical Maximum (10000)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x75, 0x10,                   //     Report Size (16)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x53,                   //     Usage (0x53)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x25, 0x08,                   //     Logical Maximum (8)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x08,                   //     Physical Maximum (8)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x55,                   //     Usage (0x55)
        0xA1, 0x02,                   //     Collection (Logical)
        0x05, 0x01,                   //       Usage Page (Generic Desktop Ctrls)
        0x09, 0x30,                   //       Usage (X)
        0x09, 0x31,                   //       Usage (Y)
        0x15, 0x00,                   //       Logical Minimum (0)
        0x25, 0x01,                   //       Logical Maximum (1)
        0x75, 0x01,                   //       Report Size (1)
        0x95, 0x02,                   //       Report Count (2)
        0x91, 0x02,                   //       Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //     End Collection
        0x05, 0x0F,                   //     Usage Page (PID Page)
        0x09, 0x56,                   //     Usage (0x56)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x95, 0x05,                   //     Report Count (5)
        0x91, 0x03,                   //     Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x57,                   //     Usage (0x57)
        0xA1, 0x02,                   //     Collection (Logical)
        0x0B, 0x01, 0x00, 0x0A, 0x00, //       Usage (0x0A0001)
        0x0B, 0x02, 0x00, 0x0A, 0x00, //       Usage (0x0A0002)
        0x66, 0x14, 0x00,             //       Unit (System: English Rotation, Length: Centimeter)
        0x55, 0xFE,                   //       Unit Exponent
        0x15, 0x00,                   //       Logical Minimum (0)
        0x26, 0xFF, 0x00,             //       Logical Maximum (255)
        0x35, 0x00,                   //       Physical Minimum (0)
        0x46, 0x68, 0x01,             //       Physical Maximum (360)
        0x66, 0x00, 0x00,             //       Unit (None)
        0x75, 0x08,                   //       Report Size (8)
        0x95, 0x02,                   //       Report Count (2)
        0x91, 0x02,                   //       Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x55, 0x00,                   //       Unit Exponent (0)
        0x66, 0x00, 0x00,             //       Unit (None)
        0xC0,                         //     End Collection
        // 0x05, 0x0F,                   //     Usage Page (PID Page)
        // 0x09, 0xA7,                   //     Usage (0xA7)
        // 0x66, 0x03, 0x10,             //     Unit (System: English Linear, Time: Seconds)
        // 0x55, 0xFD,                   //     Unit Exponent
        // 0x15, 0x00,                   //     Logical Minimum (0)
        // 0x26, 0xFF, 0x7F,             //     Logical Maximum (32767)
        // 0x35, 0x00,                   //     Physical Minimum (0)
        // 0x46, 0xFF, 0x7F,             //     Physical Maximum (32767)
        // 0x75, 0x10,                   //     Report Size (16)
        // 0x95, 0x01,                   //     Report Count (1)
        // 0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        // 0x66, 0x00, 0x00,             //     Unit (None)
        // 0x55, 0x00,                   //     Unit Exponent (0)
        0xC0,                         //   End Collection
        0x05, 0x0F,                   //   Usage Page (PID Page)
        0x09, 0x5A,                   //   Usage (0x5A)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x02,                   //     Report ID (2)
        0x09, 0x22,                   //     Usage (0x22)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x25, 0x28,                   //     Logical Maximum (40)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x28,                   //     Physical Maximum (40)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x5B,                   //     Usage (0x5B)
        0x09, 0x5D,                   //     Usage (0x5D)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x26, 0xFF, 0x00,             //     Logical Maximum (255)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x95, 0x02,                   //     Report Count (2)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x5C,                   //     Usage (0x5C)
        0x09, 0x5E,                   //     Usage (0x5E)
        0x66, 0x03, 0x10,             //     Unit (System: English Linear, Time: Seconds)
        0x55, 0xFD,                   //     Unit Exponent
        0x26, 0xFF, 0x7F,             //     Logical Maximum (32767)
        0x46, 0xFF, 0x7F,             //     Physical Maximum (32767)
        0x75, 0x10,                   //     Report Size (16)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x45, 0x00,                   //     Physical Maximum (0)
        0x66, 0x00, 0x00,             //     Unit (None)
        0x55, 0x00,                   //     Unit Exponent (0)
        0xC0,                         //   End Collection
        0x09, 0x5F,                   //   Usage (0x5F)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x03,                   //     Report ID (3)
        0x09, 0x22,                   //     Usage (0x22)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x25, 0x28,                   //     Logical Maximum (40)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x28,                   //     Physical Maximum (40)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x23,                   //     Usage (0x23)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x25, 0x01,                   //     Logical Maximum (1)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x45, 0x01,                   //     Physical Maximum (1)
        0x75, 0x04,                   //     Report Size (4)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x58,                   //     Usage (0x58)
        0xA1, 0x02,                   //     Collection (Logical)
        0x0B, 0x01, 0x00, 0x0A, 0x00, //       Usage (0x0A0001)
        0x0B, 0x02, 0x00, 0x0A, 0x00, //       Usage (0x0A0002)
        0x75, 0x02,                   //       Report Size (2)
        0x95, 0x02,                   //       Report Count (2)
        0x91, 0x02,                   //       Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //     End Collection
        0x15, 0x80,                   //     Logical Minimum (-128)
        0x25, 0x7F,                   //     Logical Maximum (127)
        0x36, 0xF0, 0xD8,             //     Physical Minimum (-10000)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x09, 0x60,                   //     Usage (0x60)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x36, 0xF0, 0xD8,             //     Physical Minimum (-10000)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x09, 0x61,                   //     Usage (0x61)
        0x09, 0x62,                   //     Usage (0x62)
        0x95, 0x02,                   //     Report Count (2)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x26, 0xFF, 0x00,             //     Logical Maximum (255)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x09, 0x63,                   //     Usage (0x63)
        0x09, 0x64,                   //     Usage (0x64)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x02,                   //     Report Count (2)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x65,                   //     Usage (0x65)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0x09, 0x6E,                   //   Usage (0x6E)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x04,                   //     Report ID (4)
        0x09, 0x22,                   //     Usage (0x22)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x25, 0x28,                   //     Logical Maximum (40)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x28,                   //     Physical Maximum (40)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x70,                   //     Usage (0x70)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x26, 0xFF, 0x00,             //     Logical Maximum (255)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x6F,                   //     Usage (0x6F)
        0x15, 0x80,                   //     Logical Minimum (-128)
        0x25, 0x7F,                   //     Logical Maximum (127)
        0x36, 0xF0, 0xD8,             //     Physical Minimum (-10000)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x71,                   //     Usage (0x71)
        0x66, 0x14, 0x00,             //     Unit (System: English Rotation, Length: Centimeter)
        0x55, 0xFE,                   //     Unit Exponent
        0x15, 0x00,                   //     Logical Minimum (0)
        0x26, 0xFF, 0x00,             //     Logical Maximum (255)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x47, 0xA0, 0x8C, 0x00, 0x00, //     Physical Maximum (35999)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x72,                   //     Usage (0x72)
        0x26, 0xFF, 0x7F,             //     Logical Maximum (32767)
        0x46, 0xFF, 0x7F,             //     Physical Maximum (32767)
        0x66, 0x03, 0x10,             //     Unit (System: English Linear, Time: Seconds)
        0x55, 0xFD,                   //     Unit Exponent
        0x75, 0x10,                   //     Report Size (16)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x66, 0x00, 0x00,             //     Unit (None)
        0x55, 0x00,                   //     Unit Exponent (0)
        0xC0,                         //   End Collection
        0x09, 0x73,                   //   Usage (0x73)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x05,                   //     Report ID (5)
        0x09, 0x22,                   //     Usage (0x22)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x25, 0x28,                   //     Logical Maximum (40)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x28,                   //     Physical Maximum (40)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x70,                   //     Usage (0x70)
        0x16, 0x04, 0x80,             //     Logical Minimum (-32764)
        0x26, 0xFF, 0x7F,             //     Logical Maximum (32767)
        0x36, 0xF0, 0xD8,             //     Physical Minimum (-10000)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x75, 0x10,                   //     Report Size (16)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0x09, 0x74,                   //   Usage (0x74)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x06,                   //     Report ID (6)
        0x09, 0x22,                   //     Usage (0x22)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x25, 0x28,                   //     Logical Maximum (40)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x28,                   //     Physical Maximum (40)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x75,                   //     Usage (0x75)
        0x09, 0x76,                   //     Usage (0x76)
        0x15, 0x80,                   //     Logical Minimum (-128)
        0x25, 0x7F,                   //     Logical Maximum (127)
        0x36, 0xF0, 0xD8,             //     Physical Minimum (-10000)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x02,                   //     Report Count (2)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0x09, 0x66,                   //   Usage (0x66)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x07,                   //     Report ID (7)
        0x05, 0x01,                   //     Usage Page (Generic Desktop Ctrls)
        0x09, 0x30,                   //     Usage (X)
        0x09, 0x31,                   //     Usage (Y)
        0x16, 0x00, 0x80,             //     Logical Minimum (-32768)
        0x26, 0xFF, 0x7F,             //     Logical Maximum (32767)
        0x75, 0x10,                   //     Report Size (16)
        0x95, 0x02,                   //     Report Count (2)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0x05, 0x0F,                   //   Usage Page (PID Page)
        0x09, 0x77,                   //   Usage (0x77)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x08,                   //     Report ID (8)
        0x09, 0x22,                   //     Usage (0x22)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x25, 0x28,                   //     Logical Maximum (40)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x28,                   //     Physical Maximum (40)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x78,                   //     Usage (0x78)
        0xA1, 0x02,                   //     Collection (Logical)
        0x09, 0x79,                   //       Usage (0x79)
        0x09, 0x7A,                   //       Usage (0x7A)
        0x09, 0x7B,                   //       Usage (0x7B)
        0x15, 0x01,                   //       Logical Minimum (1)
        0x25, 0x03,                   //       Logical Maximum (3)
        0x75, 0x08,                   //       Report Size (8)
        0x95, 0x01,                   //       Report Count (1)
        0x91, 0x00,                   //       Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //     End Collection
        0x09, 0x7C,                   //     Usage (0x7C)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x26, 0xFF, 0x7F,             //     Logical Maximum (32767)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x46, 0xFF, 0x7F,             //     Physical Maximum (32767)
        0x75, 0x10,                   //     Report Size (16)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0x09, 0x90,                   //   Usage (0x90)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x09,                   //     Report ID (9)
        0x09, 0x22,                   //     Usage (0x22)
        0x25, 0x28,                   //     Logical Maximum (40)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x28,                   //     Physical Maximum (40)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0x09, 0x96,                   //   Usage (0x96)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x0A,                   //     Report ID (10)
        0x09, 0x97,                   //     Usage (0x97)
        0x09, 0x98,                   //     Usage (0x98)
        0x09, 0x99,                   //     Usage (0x99)
        0x09, 0x9A,                   //     Usage (0x9A)
        0x09, 0x9B,                   //     Usage (0x9B)
        0x09, 0x9C,                   //     Usage (0x9C)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x25, 0x06,                   //     Logical Maximum (6)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x00,                   //     Output (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0x09, 0x7D,                   //   Usage (0x7D)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x0B,                   //     Report ID (11)
        0x09, 0x7E,                   //     Usage (0x7E)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x26, 0xFF, 0x7F,             //     Logical Maximum (32767)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x46, 0x10, 0x27,             //     Physical Maximum (10000)
        0x75, 0x10,                   //     Report Size (16)
        0x95, 0x01,                   //     Report Count (1)
        0x91, 0x02,                   //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0x05, 0x01,                   //   Usage (0x01)
        0xA1, 0x02,                   //   Collection (Logical)
        0x09, 0x00,                   //     Usage (0x86)
        0x85, 0x0C,                   //     Report ID (12)
        0x26, 0xFF, 0x00,             //     Logical Maximum (65535)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x13,                   //     Report Count (19)
        0x92, 0x02, 0x01,             //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes)
        0xC0,                         //   End Collection
        0xA1, 0x02,                   //   Collection (Logical)
        0x09, 0x00,                   //     Usage (0x86)
        0x85, 0x0D,                   //     Report ID (13)
        0x26, 0xFF, 0x00,             //     Logical Maximum (65535)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x13,                   //     Report Count (19)
        0x92, 0x02, 0x01,             //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes)
        0xC0,                         //   End Collection
        0xA1, 0x02,                   //   Collection (Logical)
        0x09, 0x00,                   //     Usage (0x86)
        0x85, 0x0E,                   //     Report ID (14)
        0x26, 0xFF, 0x00,             //     Logical Maximum (65535)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x13,                   //     Report Count (19)
        0x92, 0x02, 0x01,             //     Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes)
        0xC0,                         //   End Collection
        0x05, 0x0F,                   //   PID Usage
        0x09, 0xAB,                   //   Usage (0xAB)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x01,                   //     Report ID (1)
        0x09, 0x25,                   //     Usage (0x25)
        0xA1, 0x02,                   //     Collection (Logical)
        0x09, 0x26,                   //       Usage (0x26)
        0x09, 0x27,                   //       Usage (0x27)
        0x09, 0x30,                   //       Usage (0x30)
        0x09, 0x31,                   //       Usage (0x31)
        0x09, 0x32,                   //       Usage (0x32)
        0x09, 0x33,                   //       Usage (0x33)
        0x09, 0x34,                   //       Usage (0x34)
        0x09, 0x40,                   //       Usage (0x40)
        0x09, 0x41,                   //       Usage (0x41)
        0x09, 0x42,                   //       Usage (0x42)
        0x09, 0x43,                   //       Usage (0x43)
        0x25, 0x0B,                   //       Logical Maximum (11)
        0x15, 0x01,                   //       Logical Minimum (1)
        0x35, 0x01,                   //       Physical Minimum (1)
        0x45, 0x0B,                   //       Physical Maximum (11)
        0x75, 0x08,                   //       Report Size (8)
        0x95, 0x01,                   //       Report Count (1)
        0xB1, 0x00,                   //       Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //     End Collection
        0x05, 0x01,                   //     Usage Page (Generic Desktop Ctrls)
        0x09, 0x3B,                   //     Usage (Byte Count)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x26, 0xFF, 0x01,             //     Logical Maximum (511)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x46, 0xFF, 0x01,             //     Physical Maximum (511)
        0x75, 0x0A,                   //     Report Size (10)
        0x95, 0x01,                   //     Report Count (1)
        0xB1, 0x02,                   //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x75, 0x06,                   //     Report Size (6)
        0xB1, 0x01,                   //     Feature (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0x05, 0x0F,                   //   Usage Page (PID Page)
        0x09, 0x89,                   //   Usage (0x89)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x02,                   //     Report ID (2)
        0x09, 0x22,                   //     Usage (0x22)
        0x25, 0x28,                   //     Logical Maximum (40)
        0x15, 0x01,                   //     Logical Minimum (1)
        0x35, 0x01,                   //     Physical Minimum (1)
        0x45, 0x28,                   //     Physical Maximum (40)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0xB1, 0x02,                   //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x8B,                   //     Usage (0x8B)
        0xA1, 0x02,                   //     Collection (Logical)
        0x09, 0x8C,                   //       Usage (0x8C)
        0x09, 0x8D,                   //       Usage (0x8D)
        0x09, 0x8E,                   //       Usage (0x8E)
        0x25, 0x03,                   //       Logical Maximum (3)
        0x15, 0x01,                   //       Logical Minimum (1)
        0x35, 0x01,                   //       Physical Minimum (1)
        0x45, 0x03,                   //       Physical Maximum (3)
        0x75, 0x08,                   //       Report Size (8)
        0x95, 0x01,                   //       Report Count (1)
        0xB1, 0x00,                   //       Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //     End Collection
        0x09, 0xAC,                   //     Usage (0xAC)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x27, 0xFF, 0xFF, 0x00, 0x00, //     Logical Maximum (65534)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x47, 0xFF, 0xFF, 0x00, 0x00, //     Physical Maximum (65534)
        0x75, 0x10,                   //     Report Size (16)
        0x95, 0x01,                   //     Report Count (1)
        0xB1, 0x00,                   //     Feature (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0x09, 0x7F,                   //   Usage (0x7F)
        0xA1, 0x02,                   //   Collection (Logical)
        0x85, 0x03,                   //     Report ID (3)
        0x09, 0x80,                   //     Usage (0x80)
        0x75, 0x10,                   //     Report Size (16)
        0x95, 0x01,                   //     Report Count (1)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x27, 0xFF, 0xFF, 0x00, 0x00, //     Logical Maximum (65534)
        0x47, 0xFF, 0xFF, 0x00, 0x00, //     Physical Maximum (65534)
        0xB1, 0x02,                   //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0x83,                   //     Usage (0x83)
        0x25, 0x7F,                   //     Logical Maximum (127)
        0x45, 0x7F,                   //     Physical Maximum (127)
        0x75, 0x08,                   //     Report Size (8)
        0x95, 0x01,                   //     Report Count (1)
        0xB1, 0x02,                   //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x09, 0xA9,                   //     Usage (0xA9)
        0x09, 0xAA,                   //     Usage (0xAA)
        0x75, 0x01,                   //     Report Size (1)
        0x95, 0x02,                   //     Report Count (2)
        0x15, 0x00,                   //     Logical Minimum (0)
        0x25, 0x01,                   //     Logical Maximum (1)
        0x35, 0x00,                   //     Physical Minimum (0)
        0x45, 0x01,                   //     Physical Maximum (1)
        0xB1, 0x02,                   //     Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0x75, 0x06,                   //     Report Size (6)
        0x95, 0x01,                   //     Report Count (1)
        0xB1, 0x03,                   //     Feature (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
        0xC0,                         //   End Collection
        0xC0,                         // End Collection

        // 1174 bytes
};

/**
 * @brief usb hid descriptor
 */
#if defined(__ICCARM__) /* iar compiler */
#pragma data_alignment = 4
#endif
ALIGNED_HEAD uint8_t g_custom_hid_usb_desc[9] ALIGNED_TAIL =
    {
        0x09,               /* bLength: size of HID descriptor in bytes */
        HID_CLASS_DESC_HID, /* bDescriptorType: HID descriptor type */
        LBYTE(CUSHID_BCD_NUM),
        HBYTE(CUSHID_BCD_NUM), /* bcdHID: HID class specification release number */
        0x00,                  /* bCountryCode: hardware target conutry */
        0x01,                  /* bNumDescriptors: number of HID class descriptor to follow */
        HID_CLASS_DESC_REPORT, /* bDescriptorType: report descriptor type */
        LBYTE(sizeof(g_usbd_custom_hid_report)),
        HBYTE(sizeof(g_usbd_custom_hid_report)), /* wDescriptorLength: total length of reprot descriptor */
};

/**
 * @brief usb string lang id
 */
#if defined(__ICCARM__) /* iar compiler */
#pragma data_alignment = 4
#endif
ALIGNED_HEAD static uint8_t g_string_lang_id[USBD_CUSHID_SIZ_STRING_LANGID] ALIGNED_TAIL =
    {
        USBD_CUSHID_SIZ_STRING_LANGID,
        USB_DESCIPTOR_TYPE_STRING,
        0x09,
        0x04,
};

/**
 * @brief usb string serial
 */
#if defined(__ICCARM__) /* iar compiler */
#pragma data_alignment = 4
#endif
ALIGNED_HEAD static uint8_t g_string_serial[USBD_CUSHID_SIZ_STRING_SERIAL] ALIGNED_TAIL =
    {
        USBD_CUSHID_SIZ_STRING_SERIAL,
        USB_DESCIPTOR_TYPE_STRING,
};

/* device descriptor */
static usbd_desc_t device_descriptor =
    {
        USB_DEVICE_DESC_LEN,
        g_usbd_descriptor};

/* config descriptor */
static usbd_desc_t config_descriptor =
    {
        USBD_CUSHID_CONFIG_DESC_SIZE,
        g_usbd_configuration};

/* langid descriptor */
static usbd_desc_t langid_descriptor =
    {
        USBD_CUSHID_SIZ_STRING_LANGID,
        g_string_lang_id};

/* serial descriptor */
static usbd_desc_t serial_descriptor =
    {
        USBD_CUSHID_SIZ_STRING_SERIAL,
        g_string_serial};

static usbd_desc_t vp_desc;

/**
 * @brief  standard usb unicode convert
 * @param  string: source string
 * @param  unicode_buf: unicode buffer
 * @retval length
 */
static uint16_t usbd_unicode_convert(uint8_t *string, uint8_t *unicode_buf)
{
  uint16_t str_len = 0, id_pos = 2;
  uint8_t *tmp_str = string;

  while (*tmp_str != '\0')
  {
    str_len++;
    unicode_buf[id_pos++] = *tmp_str++;
    unicode_buf[id_pos++] = 0x00;
  }

  str_len = str_len * 2 + 2;
  unicode_buf[0] = str_len;
  unicode_buf[1] = USB_DESCIPTOR_TYPE_STRING;

  return str_len;
}

/**
 * @brief  usb int convert to unicode
 * @param  value: int value
 * @param  pbus: unicode buffer
 * @param  len: length
 * @retval none
 */
static void usbd_int_to_unicode(uint32_t value, uint8_t *pbuf, uint8_t len)
{
  uint8_t idx = 0;

  for (idx = 0; idx < len; idx++)
  {
    if (((value >> 28)) < 0xA)
    {
      pbuf[2 * idx] = (value >> 28) + '0';
    }
    else
    {
      pbuf[2 * idx] = (value >> 28) + 'A' - 10;
    }

    value = value << 4;

    pbuf[2 * idx + 1] = 0;
  }
}

/**
 * @brief  usb get serial number
 * @param  none
 * @retval none
 */
static void get_serial_num(void)
{
  uint32_t serial0, serial1, serial2;

  serial0 = *(uint32_t *)MCU_ID1;
  serial1 = *(uint32_t *)MCU_ID2;
  serial2 = *(uint32_t *)MCU_ID3;

  serial0 += serial2;

  if (serial0 != 0)
  {
    usbd_int_to_unicode(serial0, &g_string_serial[2], 8);
    usbd_int_to_unicode(serial1, &g_string_serial[18], 4);
  }
}

/**
 * @brief  get device descriptor
 * @param  none
 * @retval usbd_desc
 */
static usbd_desc_t *get_device_descriptor(void)
{
  return &device_descriptor;
}

/**
 * @brief  get device qualifier
 * @param  none
 * @retval usbd_desc
 */
static usbd_desc_t *get_device_qualifier(void)
{
  return NULL;
}

/**
 * @brief  get config descriptor
 * @param  none
 * @retval usbd_desc
 */
static usbd_desc_t *get_device_configuration(void)
{
  return &config_descriptor;
}

/**
 * @brief  get other speed descriptor
 * @param  none
 * @retval usbd_desc
 */
static usbd_desc_t *get_device_other_speed(void)
{
  return NULL;
}

/**
 * @brief  get lang id descriptor
 * @param  none
 * @retval usbd_desc
 */
static usbd_desc_t *get_device_lang_id(void)
{
  return &langid_descriptor;
}

/**
 * @brief  get manufacturer descriptor
 * @param  none
 * @retval usbd_desc
 */
static usbd_desc_t *get_device_manufacturer_string(void)
{
  vp_desc.length = usbd_unicode_convert((uint8_t *)USBD_CUSHID_DESC_MANUFACTURER_STRING, g_usbd_desc_buffer);
  vp_desc.descriptor = g_usbd_desc_buffer;
  return &vp_desc;
}

/**
 * @brief  get product descriptor
 * @param  none
 * @retval usbd_desc
 */
static usbd_desc_t *get_device_product_string(void)
{
  vp_desc.length = usbd_unicode_convert((uint8_t *)USBD_CUSHID_DESC_PRODUCT_STRING, g_usbd_desc_buffer);
  vp_desc.descriptor = g_usbd_desc_buffer;
  return &vp_desc;
}

/**
 * @brief  get serial descriptor
 * @param  none
 * @retval usbd_desc
 */
static usbd_desc_t *get_device_serial_string(void)
{
  get_serial_num();
  return &serial_descriptor;
}

/**
 * @brief  get interface descriptor
 * @param  none
 * @retval usbd_desc
 */
static usbd_desc_t *get_device_interface_string(void)
{
  vp_desc.length = usbd_unicode_convert((uint8_t *)USBD_CUSHID_DESC_INTERFACE_STRING, g_usbd_desc_buffer);
  vp_desc.descriptor = g_usbd_desc_buffer;
  return &vp_desc;
}

/**
 * @brief  get device config descriptor
 * @param  none
 * @retval usbd_desc
 */
static usbd_desc_t *get_device_config_string(void)
{
  vp_desc.length = usbd_unicode_convert((uint8_t *)USBD_CUSHID_DESC_CONFIGURATION_STRING, g_usbd_desc_buffer);
  vp_desc.descriptor = g_usbd_desc_buffer;
  return &vp_desc;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
